package com.okamura.service;

import ch.qos.logback.core.net.server.Client;
import com.okamura.domain.PostListInfo;
import com.okamura.handler.WcsClientHandler;
import com.okamura.utils.ClientConstants;
import com.okamura.utils.SpringUtil;
import com.sun.javafx.binding.StringFormatter;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.apache.log4j.Logger;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public class ResponseInfoService {
    private static final ScheduledExecutorService CONN_SCHEDULED = Executors.newScheduledThreadPool(1);
    private static final ScheduledExecutorService TASK_SCHEDULED = Executors.newScheduledThreadPool(1);
    private static Logger logger = Logger.getLogger(ResponseInfoService.class);
    //相关属性
    private final String host;
    private final int port;
    public static final int RECONNECT_DELAY_MS = 2000;
    public static final int INTERVAL_DELAY_MS = 2000;

    public static final byte HEAD_BYTE = 2;
    public static final byte TAIL_BYTE = 3;

    private NioEventLoopGroup eventLoopGroup;
    private Channel channel;
    private WcsClientHandler wcsClientHandler;
    //注入service服务
    IPostListInfoService postListInfoService = (IPostListInfoService) SpringUtil.getBean("postListInfoServiceImpl");

    private final AtomicInteger failConnectedTime = new AtomicInteger(0);
    private final AtomicInteger currentState = new AtomicInteger(ClientConstants.CLIENT_STATUS_OFF);
    private final AtomicBoolean shouldRetry = new AtomicBoolean(true);

    public ResponseInfoService(String host, int port) {
        this.host = host;
        this.port = port;
    }

    /**
     * 配置启动类
     *
     * @return
     */
    private Bootstrap initClientBootStrap() {
        Bootstrap b = new Bootstrap();
        eventLoopGroup = new NioEventLoopGroup();
        b.group(eventLoopGroup)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        wcsClientHandler = new WcsClientHandler(currentState, disconnectCallback);
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast("decoder", new StringDecoder());
                        pipeline.addLast("encoder", new StringEncoder());
                        pipeline.addLast(wcsClientHandler);
                    }
                });
        return b;
    }

    /**
     * 与服务器建立通讯
     *
     * @param b
     */
    private void connect(Bootstrap b) {
        b.connect(host, port)
                .addListener((GenericFutureListener<ChannelFuture>) future -> {
                    if (future.cause() != null) {
                        logger.warn(String.format("[Merro-Client] Could not connect to <%s:%d> after %d times"
                                , host, port, failConnectedTime.get()));
                        failConnectedTime.incrementAndGet();
                        channel = null;
                    } else {
                        failConnectedTime.set(0);
                        channel = future.channel();
                        logger.info("[Merro-Client] Connect Success!");
                    }
                });
    }

    /**
     * 服务重连线程
     */
    private Runnable disconnectCallback = new Runnable() {
        @Override
        public void run() {
            if (!shouldRetry.get()) {
                return;
            }
            CONN_SCHEDULED.schedule(new Runnable() {
                @Override
                public void run() {
                    logger.warn("[Merro-Client] Reconnecting to server");
                    try {
                        startInternal();
                    } catch (Exception e) {
                        logger.error("[Merro-Client] Failed to reconnect to server");
                    }
                }
            }, RECONNECT_DELAY_MS * (failConnectedTime.get() + 1), TimeUnit.MILLISECONDS);
            clearUp();
        }
    };

    public boolean isReady() {
        return channel != null && wcsClientHandler != null && wcsClientHandler.hasStarted();
    }

    /**
     * 业务线程
     */
    private void executorTask() {
        TASK_SCHEDULED.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                if (isReady()) {
                    sendPostInfo();
                } else {
                    return;
                }
            }
        }, INTERVAL_DELAY_MS, INTERVAL_DELAY_MS, TimeUnit.MILLISECONDS);
    }


    /**
     * 开放外部调用
     */
    public void start() {
        startInternal();
//        executorBusiness.run();
        executorTask();
    }

    private void startInternal() {
        connect(initClientBootStrap());
    }

    /**
     * 关闭相关通道
     */
    private void clearUp() {
        if (channel != null) {
            channel.close();
            channel = null;
        }
        if (eventLoopGroup != null) {
            eventLoopGroup.shutdownGracefully();
        }
    }

    private void sendPostInfo() {
        PostListInfo postInfo = postListInfoService.getPostInfo();
        if (postInfo == null) {
            return;
        }
        postInfo.setPostSt("1");//将状态更新为[发送中...]
        String postMsg = postInfo.getPostMsg();
        postListInfoService.updatePostInfo(postInfo);
//        postListInfoService

        //String postMsg = "|CZ1|PTLPN|10004343|1336598|1CA060101|60|";
        //创建一个ByteBuf,并写入信息
        ByteBuf byteBuf = Unpooled.buffer(100);
        byteBuf.writeByte(HEAD_BYTE);
        byteBuf.writeBytes(postMsg.getBytes(StandardCharsets.UTF_8));
        byteBuf.writeByte(TAIL_BYTE);
        channel.writeAndFlush(byteBuf.toString(CharsetUtil.UTF_8));
        //向客户端发送信息
        logger.info("[Merro-Client] Send message[" + byteBuf.toString(CharsetUtil.UTF_8) + "]");
        byteBuf.clear();
    }

}
